package dxunderground.chatbot;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileWriter;
import java.io.IOException;
import java.util.List;
import java.util.Scanner;

import org.jdom.Document;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.input.SAXBuilder;
import org.jdom.output.Format;
import org.jdom.output.XMLOutputter;

import dxunderground.utilities.io.ObjSerialization;
import dxunderground.utilities.math.Random;

/**
 * This version of the bot is not creative. It will only respond in the same
 * manor that it has already seen.
 * 
 * @author Paul Robertson
 */
public class CopyBot implements Bot {
	private Element personality;
	private File location;
	private boolean started = false;
	private String lastResponse;
	private boolean toSerialize;

	public CopyBot(boolean toSerialize) {
		this.personality = new Element("Personality");
		this.location = null;
		this.lastResponse = null;
		this.toSerialize = toSerialize;
	}

	public CopyBot(String location, boolean toSerialize) throws JDOMException, IOException {
		this(new File(location), toSerialize);
	}

	public CopyBot(File location, boolean toSerialize) throws JDOMException, IOException {
		Element personality = this.loadPersonality(location, toSerialize);
		if (personality == null)
			personality = new Element("Personality");
		this.personality = personality;
		this.location = location;
		this.lastResponse = null;
		this.toSerialize = toSerialize;
	}

	public synchronized Element addRequest(String request) {
		Element elem = getChildWithText(this.personality, request);
		if (elem != null)
			return elem;

		elem = new Element("Request");
		elem.setText(request);
		this.personality.addContent(elem);
		return elem;
	}

	public synchronized Element addResponse(Element request, String response) {
		Element elem = getChildWithText(request, response);
		if (elem != null)
			return elem;

		Element responseElem = new Element("Response");
		responseElem.setText(response);
		request.addContent(responseElem);

		elem = getChildWithText(this.personality, response);
		if (elem == null)
			addRequest(response);

		return responseElem;
	}

	@SuppressWarnings("unchecked")
	private Element getChildWithText(Element elem, String text) {
		List<Element> requestList = elem.getChildren();
		for (Element clild : requestList) {
			if (clild.getText().equalsIgnoreCase(text)) {
				return clild;
			}
		}
		return null;
	}

	public synchronized String getNewResponse() {
		System.out.println("No Data. Input valid response");
		Scanner in = new Scanner(System.in);
		return in.nextLine();
	}

	@SuppressWarnings("unchecked")
	public synchronized Element getResponse(String request) {
		Element req = getChildWithText(this.personality, request);
		if (req == null) {
			req = this.addRequest(request);
		}

		List list = req.getChildren();
		int numResponses = list.size();
		Element response;
		if (numResponses > 0) {
			response = (Element) list.get(Random.randomCap(numResponses - 1));
		} else {
			response = addResponse(req, this.getNewResponse());
		}

		if (this.lastResponse != null) {
			Element lastResponse = getChildWithText(this.personality, this.lastResponse);
			Element child = getChildWithText(lastResponse, request);
			if (child == null) {
				child = new Element("Response");
				child.setText(request);
				lastResponse.addContent(child);
			}
		}
		this.lastResponse = response.getText();
		return response;
	}

	public synchronized Element loadPersonality(String location, boolean toSerialized) throws JDOMException, IOException {
		if (toSerialized)
			return (Element) ObjSerialization.read(location).get(0);

		return loadPersonality(new File(location), toSerialized);
	}

	public synchronized Element loadPersonality(File location, boolean toSerialized) throws JDOMException, IOException {
		if (toSerialized)
			return (Element) ObjSerialization.read(location).get(0);
		SAXBuilder builder = new SAXBuilder();
		try {
			Document doc = builder.build(location);
			return doc.getRootElement();
		} catch (FileNotFoundException e) {
			return new Element("Personality");
		}
	}

	public synchronized void savePersonality(String location, boolean toSerialized) throws IOException {
		savePersonality(new File(location), toSerialized);
	}

	public synchronized void savePersonality(File location, boolean toSerialized) throws IOException {
		if (toSerialized)
			ObjSerialization.write(this.personality, location);
		XMLOutputter out = new XMLOutputter(Format.getPrettyFormat());
		FileWriter fout = new FileWriter(location);
		out.output(this.personality, fout);
		fout.close();
	}

	public void run() {
		Scanner in = new Scanner(System.in);
		String response;
		String input;
		while (in.hasNext()) {
			input = in.nextLine();
			if (input.equalsIgnoreCase("exit"))
				break;
			response = getResponse(input).getText();
			System.out.println(response);
		}
		in.close();
		if (this.location != null) {
			try {
				this.savePersonality(this.location, this.toSerialize);
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}

	public void exe() {
		if (!this.started)
			new Thread(this, CopyBot.class.getCanonicalName()).start();
	}

	public static void main(String[] args) throws JDOMException, IOException {
		args = new String[1];
		args[0] = "C:/BotTest.xml";

		Bot bot;
		if (args.length > 0)
			bot = new CopyBot(args[0], false);
		else
			bot = new CopyBot(false);
		bot.exe();
	}
}